<?php

namespace App\Services\WxQrcode;

use App\Facades\EasyWechat;
use App\Models\WxQrcode;
use App\Models\WxQrcodeUse;
use App\Models\WxQrcodeScanlog;
use App\Services\WxCommon\WxError;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * 微信二维码服务类
 * @package App\Services
 */
class WxQrcodeService  extends \App\Services\WxCommon\WxBase
{
    /**
     * 生成获取二维码
     * @param bool $isForever
     * @return mixed
     * @throws \Exception
     */
    public function generateQrCodeId($isForever = false)
    {
        Db::beginTransaction();
        try {
            $findFree = WxQrcode::onlyTrashed()->where('appid', $this->appid)->where('is_forever', (int)$isForever)->first();
            if ($findFree && !empty($findFree['expire_time']) && strtotime($findFree['expire_time']) - 86400 > time()) {
                return $findFree['qrcode_id'];
            }
            //恢复二维码
            $expireSeonds = 30 * 86400;
            if ($findFree) {
                $findFree->restore();
            } else {
                $findFree = new WxQrcode;
            }
            //计算出新的场景ID，因为事务回滚后自增ID不会回滚，所以采用手动计算的形式
            $count = WxQrcode::withTrashed()->where('appid', $this->appid)->count();
            $findFree->qrcode_id = $count + 1;
            if ($isForever) {//永久二维码
                $findFree->expire_time = null;
                $findFree->is_forever = 1;
            } else {//临时二维码
                $findFree->expire_time = time() + $expireSeonds;
                $findFree->is_forever = 0;
            }

            $qrcodeId = $findFree->qrcode_id;
            $app = EasyWechat::officialAccount($this->appid);
            if ($isForever) {
                $apiRs = $app->qrcode->forever($qrcodeId);
            } else {
                $apiRs = $app->qrcode->temporary($qrcodeId, $expireSeonds);
            }
            //检查微信接口返回结果
            WxError::checkApiResponse($apiRs);
            if (empty($apiRs['ticket'])) {
                throw new \Exception('获取二维码失败');
            }
            $findFree->ticket = $apiRs['ticket'];
            $findFree->url = $apiRs['url'];
            $findFree->save();
            Db::commit();
        } catch (\Exception $e) {
            Db::rollBack();
            throw new \Exception($e->getMessage());
        }
        return $qrcodeId;
    }

    /**
     * 释放二维码
     * @param $qrCodeId
     * @return mixed
     */
    public function releaseQrCodeId($qrCodeId)
    {
        $find = WxQrcode::where('appid', $this->appid)->findOrFail($qrCodeId);
        return $find->delete();
    }

    /**
     * 保存二维码用途数据
     * @param array $qrCodeData
     * @return array
     * @throws \Exception
     */
    public function saveQrcodeUse($qrCodeData = [])
    {
        Db::beginTransaction();
        try {
            $id = $qrCodeData['id'] ?? '';
            if (empty($qrCodeData['group_id'])) {
                throw new \Exception('请选择分组');
            }
            $groupService = new WxQrcodeGroupService($this->appid);
            //获取分组数据
            $groupData = $groupService->getGroupDataById($qrCodeData['group_id']);
            if (empty($groupData)) {
                throw new \Exception('无效的分组');
            }
            if (empty($qrCodeData['name'])) {
                throw new \Exception('请填写二维码名称');
            }
            if ($id) {
                $qrcodeUse = WxQrcodeUse::where('appid', $this->appid)->findOrFail($id);

                $originGroupData = $groupService->getGroupDataById($qrcodeUse['group_id']);
                //切换分组且二维码类别变更后重新获取二维码
                if ($groupData['is_forever'] != $originGroupData['is_forever']) {
                    //释放上一个二维码
                    $this->releaseQrCodeId($qrcodeUse['qrcode_id']);
                    //生成新的二维码
                    $qrcodeUse->qrcode_id = $this->generateQrCodeId((bool)$groupData['is_forever']);

                }
            } else {
                $qrcodeUse = new WxQrcodeUse;
                //获取新的二维码
                $qrcodeUse->qrcode_id = $this->generateQrCodeId((bool)$groupData['is_forever']);
            }
            $qrcodeUse->appid = $this->appid;
            $qrcodeUse->group_id = $qrCodeData['group_id'];
            $qrcodeUse->name = $qrCodeData['name'] ?? '';
            $qrcodeUse->description = $qrCodeData['description'] ?? '';
            $qrcodeUse->relation_id = $qrCodeData['relation_id'] ?? '';
            $qrcodeUse->save();

            Db::commit();
        } catch (\Exception $e) {
            Db::rollBack();
            throw new \Exception($e->getMessage());
        }
        return $qrcodeUse->toArray();
    }

    /**
     * 释放二维码用途数据
     * @param $qrCodeId
     * @return mixed
     * @throws \Exception
     */
    public function releaseQrcodeUse($qrCodeId)
    {
        if (empty($qrCodeId)) {
            throw new \Exception('请输入二维码');
        }
        //二维码用途释放
        $findUse = WxQrcodeUse::where('appid', $this->appid)->where('qrcode_id', $qrCodeId)->firstOrFail();
        $findUse->delete();
        //二维码释放
        return $this->releaseQrCodeId($qrCodeId);
    }

    /**
     * 获取二维码用途数据
     * @param $qrCodeId
     * @return mixed
     */
    public function getQrcodeUse($qrCodeId)
    {
        $findUse = WxQrcodeUse::where('appid', $this->appid)->where('qrcode_id', $qrCodeId)->firstOrFail();
        $findUse['group'] = $findUse->group;
        $useData = $findUse->toArray();

        $findQrcode = WxQrcode::where('appid', $this->appid)->findOrFail($qrCodeId);
        //二维码类
        $app = EasyWechat::officialAccount($this->appid);
        if (!$findQrcode['is_forever']) {
            $expireSeonds = 30 * 86400;
            $apiRs = $app->qrcode->temporary($findQrcode['qrcode_id'], $expireSeonds);
            //检查微信接口返回结果
            WxError::checkApiResponse($apiRs);
            $findQrcode->ticket = $apiRs['ticket'];
            $findQrcode->url = $apiRs['url'];
            $findQrcode->save();
        }
        $qrcodeData = $findQrcode->toArray();
        //二维码获取网址
        $qrcodeData['qrcode_url'] = $app->qrcode->url($qrcodeData['ticket']);
        return array_merge($useData, $qrcodeData);
    }

    /**
     * 扫码处理
     * @param $eventData
     */
    public function scanHandle($eventData)
    {
        try{
            //二维码ID
            $qrCodeId = str_replace('qrscene_', '', $eventData['EventKey']);
            $qrCodeId = (int)$qrCodeId;
            //二维码数据
            $qrCodeData = $this->getQrcodeUse($qrCodeId);
            //记录扫码日志
            WxQrcodeScanlog::create([
                'appid' => $this->appid,
                'qrcode_id' => $qrCodeId,
                'group_id' => $qrCodeData['group_id'],
                'from_openid' => $eventData['FromUserName'],
                'relation_id' => $qrCodeData['relation_id'],
                'event' => $eventData['Event'],
                'ticket' => $eventData['Ticket'],
            ]);
            //处理业务逻辑
            $groupKey = $qrCodeData['group']['group_key'] ?? '';
            if (empty($groupKey)) {
                throw new \Exception('分组定义无效');
            }
            $objName = __NAMESPACE__ . '\WxQrcode\\Handle' . ucfirst($groupKey);
            $obj = new $objName;
            if ($obj->isInstantiable) {
                $obj->scanHandle($eventData, $qrCodeData);
            } else {
                Log::error("类[{$objName}]不可实例化");
            }
        }catch (\Exception $e){
            Log::error($e->getMessage());
        }
    }
}